package key

import (
	"fmt"
	"time"
)

func AccessC() {
	ChannelBaseLearn()
}

type Cat struct {
	Name string
	Age  int
}

// ChannelBaseLearn 管道学习
func ChannelBaseLearn() {
	// 创建管道
	/*var intChan chan int
	intChan = make(chan int, 3)*/

	// 写入数据
	/*intChan <- 10
	num := 211
	intChan <- num
	intChan <- 50
	fmt.Printf("管道的长度：%v\n管道的容量：%v\n", len(intChan), cap(intChan))*/

	// 读取数据
	/*var num2 int
	num2 = <-intChan
	fmt.Println()
	fmt.Println("num2=", num2)
	fmt.Println()
	fmt.Printf("管道的长度：%v\n管道的容量：%v\n", len(intChan), cap(intChan))*/

	// channel练习
	// 可以存放任意数据类型的管道
	/*var allChan chan interface{}
	allChan = make(chan interface{}, 3)
	allChan <- 10
	allChan <- "tom jack"
	cat := Cat{
		Name: "tom",
		Age:  10,
	}
	allChan <- cat

	<-allChan
	<-allChan

	// 读取第三个元素
	newCat := <-allChan
	fmt.Printf("newCat的数据类型是：%T\n newCat的值是：%v\n", newCat, newCat)
	// 类型断言
	a := newCat.(Cat)
	fmt.Printf("newCat.Name=%v\n", a.Name)*/

	/*channel的关闭 --begin--*/
	/*intChan := make(chan int, 3)
	intChan <- 100
	intChan <- 200
	close(intChan)
	// intChan <- 300 // 此时无法写入数据进去
	n1 := <-intChan
	fmt.Println(n1) // 但是可以读取数据*/
	/*channel的关闭 --end--*/

	/*channel的遍历 --begin--*/
	/*intChan2 := make(chan int, 100)
	for i := 0; i < 100; i++ {
		intChan2 <- i * 2
	}
	close(intChan2)
	// 切记要有range进行遍历，不要用for
	for v := range intChan2 {
		fmt.Println("v=", v)
	}*/
	/*channel的遍历 --end--*/

	/*goroutine和channel结合使用 --begin--*/
	// intChan3 := make(chan int, 10)
	// exitChan := make(chan bool, 1)
	// go WriteChan(intChan3)
	// go ReadChan(intChan3, exitChan)
	// for {
	// 	_, ok := <-exitChan
	// 	if !ok {
	// 		fmt.Println(ok)
	// 		break
	// 	}
	// 	/*v, _ := <-exitChan
	// 	if v {
	// 		fmt.Println(v)
	// 		break
	// 	}*/
	// }
	/*goroutine和channel结合使用 --end--*/

	/*利用管道和协程求解素数--begin--*/
	// intChan4 := make(chan int, 10000)
	// primeChan := make(chan int, 50000)
	// exitChan := make(chan bool, 4)
	//
	// start := time.Now().Unix()
	// go WriteIntChan4(intChan4)
	// for i := 0; i < 4; i++ {
	// 	go ReadPrimeChan(intChan4, primeChan, exitChan)
	// }
	//
	// go func() {
	// 	/*var count int = 0
	// 	for v := range exitChan {
	// 		if v == true {
	// 			count++
	// 		}
	// 		if count == 4 {
	// 			close(primeChan)
	// 			close(exitChan)
	// 		}
	// 	}*/
	// 	for i := 0; i < 4; i++ {
	// 		num := <-exitChan
	// 		fmt.Println(num)
	// 	}
	// 	close(primeChan)
	// 	close(exitChan)
	// }()
	// for {
	// 	_, ok := <-primeChan
	// 	if !ok {
	// 		break
	// 	}
	// 	// fmt.Printf("素数=%d\n", res)
	// }
	// end := time.Now().Unix()
	// fmt.Println("start=", start)
	// fmt.Println()
	// fmt.Println("end=", end)
	// fmt.Printf("整个程序消耗的时长是：%s\n", strconv.FormatInt(end-start, 10))
	/*利用管道和协程求解素数--end--*/

	/*管道类型 --begin--*/
	// ChannelBaseLearn2()
	/*管道类型 --end--*/

	/*channel select --begin--*/
	// ChannelSelect()
	/*channel select --end--*/

	/*多个协程运行时，一个协程挂掉，不能阻断其他协程进行 --begin--*/
	ChannelGoroutine()
	/*多个协程运行时，一个协程挂掉，不能阻断其他协程进行 --end--*/
}

func ChannelGoroutine()  {

}

func ChannelSelect() {
	intChan := make(chan int, 10)
	for i := 0; i < 10; i++ {
		intChan <- i
	}

	strChan := make(chan string, 5)
	for i := 0; i < 5; i++ {
		strChan <- "hello" + fmt.Sprintf("%d", i)
	}

	// 传统的方法循环遍历管道时，如果不关闭管道，导致deadlock
	// 使用select进行解决
	for {
		select {
		case v := <-intChan: // 如果intChan一直没有关闭，不会一直阻塞而deadlock
			fmt.Printf("从intChan读取数据%d\n", v)
			time.Sleep(time.Second)
		case v := <-strChan:
			fmt.Printf("strChan读取数据%s\n", v)
			time.Sleep(time.Second)
		default:
			fmt.Printf("找不到管道了，不管了，直接结束！\n")
			return
		}
	}
}

func ChannelBaseLearn2() {
	// 声明为只写
	var chan2 chan<- int
	chan2 = make(chan int, 3)
	fmt.Println(chan2)

	// 声明为只读
	var chan3 <-chan int
	chan3 = make(chan int, 3)
	fmt.Println(chan3)
}

func WriteIntChan4(intChan4 chan int) {
	for i := 0; i < 500000; i++ {
		intChan4 <- i
	}
	close(intChan4)
}

func ReadPrimeChan(intChan4 chan int, primeChan chan int, exitChan chan bool) {
	var num int
	var ok bool
	var flag bool
	for {
		flag = true
		num, ok = <-intChan4
		if !ok {
			break
		}
		for i := 2; i < num; i++ {
			if num%i == 0 {
				flag = false
				break
			}
		}
		if flag {
			primeChan <- num
		}
	}
	fmt.Println("有一个primeChan 协程因为取不到数据，退出")
	exitChan <- true
}

func WriteChan(intChan chan int) {
	for i := 1; i <= 50; i++ {
		intChan <- i
		fmt.Printf("writeChan 写入的数据是=%v\n", i)
	}
	close(intChan)
}

func ReadChan(intChan chan int, exitChan chan bool) {
	for {
		v, ok := <-intChan
		if !ok {
			break
		}
		time.Sleep(time.Second)
		fmt.Printf("readChan 读到的数据是=%v\n", v)
	}
	exitChan <- true
	close(exitChan)
}
